<template>
  <div id="well"
       class="container">
    <div class="row phyd3-controls well">
      <div v-if="showTag"
           class="col-xs-3">
        <a-col :span="6">
          <div class="form-group">
            <div class="checkbox">
              <label>
                <input id="phylogram"
                       type="checkbox"
                       checked="checked"> 进化树型
              </label>
            </div>
          </div>
          <div class="form-group">
            <div class="checkbox">
              <label>
                <input id="nodeNames"
                       type="checkbox"
                       checked="checked"> 节点名称
              </label>
            </div>
          </div>
          <div class="row node-box">
            <div class="col-xs-3 text-right left-dropdown middle-padding">显示</div>
            <div class="col-xs-5 no-padding">
              <select id="nodesType"
                      class="form-control">
                <option selected="selected">所有</option>
                <option>仅节点名</option>
                <option>分支名</option>
              </select>
            </div>
            <div class="col-xs-4 text-left right-dropdown middle-padding">
              节点
            </div>
          </div>
        </a-col>
        <!-- <a-col :span="4">
          <div class="form-group">
            <div class="checkbox">
              <label>
                <input id="graphs"
                       type="checkbox"
                       checked="checked"> 变异热图
              </label>
            </div>
          </div>
          <div class="form-group">
            <div class="checkbox">
              <label>
                <input id="graphLegend"
                       type="checkbox"
                       checked="checked"> 图例
              </label>
            </div>
          </div>
        </a-col> -->
        <a-col :span="8">
          <div class="row">
            <div class="col-xs-4 col-xs-offset-4 text-center">
              <button id="zoominY"
                      class="btn btn-primary"
                      title="zoom in along Y axis"><span class="glyphicon glyphicon-zoom-in"
                      aria-hidden="true"></span> Y</button>
            </div>
          </div>
          <div class="row">
            <div class="col-xs-4 text-center">
              <button id="zoomoutX"
                      class="btn btn-primary"
                      title="zoom out along X axis"><span class="glyphicon glyphicon-zoom-out"
                      aria-hidden="true"></span> X</button>
            </div>
            <div class="col-xs-4 text-center">
              <button id="resetZoom"
                      class="btn btn-link">重置</button>
            </div>
            <div class="col-xs-4 text-center">
              <button id="zoominX"
                      class="btn btn-primary"
                      title="zoom in along X axis"><span class="glyphicon glyphicon-zoom-in"
                      aria-hidden="true"></span> X</button>
            </div>
          </div>
          <div class="row">
            <div class="col-xs-4 col-xs-offset-4 text-center">
              <button id="zoomoutY"
                      class="btn btn-primary"
                      title="zoom out alongY axis"><span class="glyphicon glyphicon-zoom-out"
                      aria-hidden="true"></span> Y</button>
            </div>
          </div>
        </a-col>
        <a-col :span="6">
          <template v-if="type === 'flu'">
            <div class="tip">
              <span>下载:
                &nbsp;
                <button class="btn btn-primary"
                        id="linkSVG">SVG</button>&nbsp;
                <button class="btn btn-primary"
                        id="linkPNG">PNG</button>
              </span>
              <div v-if="legends.length"
                   class="tip">
                图例:
                <template v-for="(item,index) in legends"
                          :key="index">
                  <a-row>
                    {{item.label}}:
                    <div :id="'legend'+index"></div>
                  </a-row>
                </template>
              </div>
            </div>
          </template>
          <template v-if="type === 'ncov'">
            <div class="tip">分类来源
              <span :title="tip">
                <i class="el-icon-info"></i>
              </span>: 【<a href="https://www.gisaid.org/"
                 target="_blank">Gisaid数据库</a>】
            </div>
            <div class="tip">
              <span>下载:
                <a target="_blank"
                   :href="downloadUrl"
                   class="tree-tip">树文件</a>
                <a target="_blank"
                   :href="downloadMatrixUrl">矩阵文件</a>
                &nbsp;
                <button class="btn btn-primary"
                        id="linkSVG">SVG</button>&nbsp;
                <button class="btn btn-primary"
                        id="linkPNG">PNG</button>
              </span>
            </div>
            <div class="tip">图例：<div id="legend"></div>
            </div>
          </template>
        </a-col>
      </div>
      <div id="phyd3"
           class="col-xs-12"></div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, unref, onMounted, PropType, watch } from 'vue';
import * as d3 from 'd3';

const opts = {
  dynamicHide: false,
  height: document.body.scrollHeight,
  invertColors: false,
  lineupNodes: true,
  showDomains: false,
  showDomainNames: false,
  showDomainColors: true,
  showGraphs: true,
  showGraphLegend: true,
  showLength: true,
  showNodeNames: true,
  showNodesType: 'all',
  showPhylogram: true,
  showTaxonomy: true,
  showFullTaxonomy: false,
  showSequences: false,
  showTaxonomyColors: true,
  backgroundColor: '#f5f5f5',
  foregroundColor: '#000000',
  nanColor: '#f5f5f5',
  scaleX: 0.8,
};

const stringToXml = (xmlString: any) => {
  let xmlDoc;
  if (typeof xmlString === 'string') {
    if (document.implementation.createDocument) {
      const parser = new DOMParser();
      xmlDoc = parser.parseFromString(xmlString, 'text/xml');
    } else if (window.ActiveXObject) {
      xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
      xmlDoc.async = false;
      xmlDoc.loadXML(xmlString);
    }
  } else {
    xmlDoc = xmlString;
  }
  return xmlDoc;
};

// 进化树图例
const legend = (obj: any, index: number) => {
  const labelTip = obj.arr.map((item: any) => item.name);
  const colors = obj.arr.map((item: any) => item.value);
  const color = d3.scaleOrdinal().domain(labelTip).range(colors);

  const g = d3
    .select(`#legend${index} svg`)
    .selectAll('g')
    .data(color.domain())
    .join('g')
    .attr('transform', (d: any, i: number) => `translate(${i * 35}, 0)`);

  g.append('title').text((d: any, i: number) => labelTip[i]);
  g.append('rect').attr('width', 30).attr('height', 30).attr('fill', color);
  g.append('text')
    .attr('x', 15)
    .attr('y', 15)
    .text((d: any) => d.substr(0, 1))
    .attr('fill', '#fff')
    .attr('text-anchor', 'middle')
    .attr('dominant-baseline', 'middle');
};

const colors = [
  '#2ca02c',
  '#1f77b4',
  '#ff7f0e',
  '#922f51',
  '#b2a534',
  '#554d4d',
  '#b80028',
  '#000000',
];

const labelName = ['S', 'L', 'V', 'G', 'GH', 'GR', 'GV', 'O'];

const labelTip = [
  'S类群包含以下变异位点 C8782T,T28144C',
  'L类群包含以下变异位点 C241,C3037,A23403,C8782,G11083,G25563,G26144,T28144,G28882',
  'V类群包含以下变异位点 G11083T,G26144T',
  'G类群包含以下变异位点 C241T,C3037T,A23403G',
  'GH类群包含以下变异位点 C241T,C3037T,A23403G,G25563T',
  'GR类群包含以下变异位点 C241T,C3037T,A23403G,G28882A',
  'GV类群包含以下变异位点 C241T,C3037T,A23403G,C22227T',
  '不属于以上七种变异类型的',
];

const color = d3.scaleOrdinal().domain(labelName).range(colors);

const ncovLegend = (svg) => {
  const g = svg
    .selectAll('g')
    .data(color.domain())
    .join('g')
    .attr('transform', (d, i) => `translate(${i * 35}, 0)`);

  g.append('title').text((d, i) => labelTip[i]);
  g.append('rect').attr('width', 30).attr('height', 30).attr('fill', color);
  g.append('text')
    .attr('x', 15)
    .attr('y', 15)
    .text((d) => d)
    .attr('fill', '#fff')
    .attr('text-anchor', 'middle')
    .attr('dominant-baseline', 'middle');
};

export default defineComponent({
  props: {
    // 进化树数据
    value: {
      type: String,
      default: '',
    },
    // 可选值为 ncov, flu
    type: {
      type: String,
      default: '',
    },
    // 进化树图例名称，暂支持type为flu类型
    legend: {
      type: Array,
      default: [],
    },
    // 显示操作框
    showTag: {
      type: Boolean as PropType<boolean>,
      default: true,
    },
    // 任务id
    dataId: {
      type: String,
      default: '',
    },
    // barcode id
    barcodeId: {
      type: String,
      default: '',
    },
    // 高亮名称
    sampleNames: {
      type: Array,
      default: [],
    },
    // chart extra height, default 800px
    height: {
      type: Number,
      default: 800,
    },
  },

  setup(props) {
    const legends = ref<any>([]);

    const downloadUrl = ref('');
    const downloadMatrixUrl = ref('');

    const getLegendData = (data: any) => {
      Object.keys(data).forEach((item, index) => {
        legends.push({ label: item, arr: [] });
        Object.keys(data[item]).forEach((j) => {
          legends[index].arr.push({ name: j, value: data[item][j] });
        });
      });
      setTimeout(() => {
        legends.forEach((item: any, index: number) => {
          getLegend(item, index);
        });
      }, 100);
    };

    const getLegend = async (item: any, index: number) => {
      const svg = d3
        .select(`#legend${index}`)
        .append('svg')
        .attr('height', 30)
        .attr('width', 300)
        .call(legend(item, index));
      await svg.call(legend(item, index));
    };

    const getNcovLengend = () => {
      const svg = d3.select('#legend').append('svg').attr('height', 30).attr('width', 340);
      svg.call(ncovLegend);
    };

    // 高亮节点名称
    const highlightText = () => {
      const data = d3.select('#phyd3').select('#main').selectAll('.leaf').selectAll('text');
      data._groups.forEach((item: any) => {
        props.sampleNames.forEach((j: any) => {
          if (item[0].textContent.indexOf(j) > -1) {
            item[0].scrollIntoView();
            item[0].attributes.stroke.value = null;
            item[0].attributes.fill.value = '#f44336';
          }
        });
      });
    };

    const init = () => {
      d3.select('#phyd3').text('Loading...');
      Object.assign(opts, {
        height: props.height,
      });

      d3.select('#phyd3').text(null);
      const tree = phyd3.phyloxml.parse(stringToXml(props.value));
      if (props.legend && props.legend.length > 0) {
        getLegendData(props.legend);
      } else if (props.type === 'ncov') {
        getNcovLengend();
      }
      if (props.sampleNames) {
        highlightText();
        getUrl();
      }
      phyd3.phylogram.build('#phyd3', tree, opts);
    };

    const getUrl = () => {
      let path;
      if (props.sampleNames[0] === 'sample') {
        path = `/outputs/${props.dataId}/fastq_analysis`;
      } else {
        path = `/outputs/${props.dataId}/fastq_analysis/${props.sampleNames[0]}`;
      }
      downloadUrl.value = `${path}/list_snp.nwk`;
      downloadMatrixUrl.value = `${path}/combine_snp.matrix`;
    };

    watch(props, () => {
      init();
    });

    return {
      legends,
      downloadUrl,
      downloadMatrixUrl,
    };
  },
});
</script>

<style lang="less" scoped>
.container {
  width: 100%;
  height: 100%;
  text-align: left;
}

.col-xs-12 {
  width: 100%;
}

.well {
  margin-bottom: 0;
  padding: 10px 20px;
  display: flex;
  flex-direction: column;
  min-width: 1200px;
  overflow: auto;
  background-color: #fff;
}

.form-group {
  margin-bottom: 5px;

  .checkbox label {
    font-size: 16px;
  }
}

.col-xs-3 {
  width: 100%;
  display: inherit;

  .row,
  .form-control {
    font-size: 16px;
    margin-bottom: 2px;
  }
}

.node-box {
  .col-xs-3 {
    width: 20%;
  }

  .col-xs-5 {
    width: 30%;
  }
}

.tip {
  font-size: 14px;
  color: #000000;
  padding-top: 10px;
  word-break: keep-all;
  margin-bottom: 4px;
  display: inline-flex;

  .el-row {
    display: inline-flex;
  }

  .tree-tip {
    margin-right: 10px;
  }
}
</style>